package com.amumu.drama.common.base.aspects;

import com.amumu.drama.common.base.annonation.Idempotent;
import com.amumu.drama.common.utils.IdempotentUtil;
import com.amumu.drama.common.utils.SpelUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

@Aspect
@Component
public class IdempotentAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(IdempotentAspect.class);
    @Resource
    private IdempotentUtil idempotentUtil;

    @Around("@annotation(com.amumu.drama.common.base.annonation.Idempotent)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            MethodSignature methodSignature = (MethodSignature) (joinPoint.getSignature());
            Method method = joinPoint.getTarget().getClass().getDeclaredMethod(methodSignature.getName(), methodSignature.getMethod().getParameterTypes());
            Idempotent idempotent = method.getAnnotation(Idempotent.class);

            if (null != idempotent && null != idempotent.key()) {
                String key = SpelUtil.generateKeyBySpEL(idempotent.key(), joinPoint);
                boolean isIdempotent = idempotentUtil.isIdempotent(String.format("%s_%s", method.getName(), key), idempotent.expireTime());
                if (isIdempotent) {
                    LOGGER.info("重复请求{}", idempotent.key());
                    throw new IllegalStateException("Duplicate request detected");
                }
            }
        } catch (Exception e) {
            LOGGER.error("Idempotent注解解析异常", e);
        }
        return joinPoint.proceed();
    }
}
